package com.stsmobile;

import android.app.Application; 

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import com.serverconnection.HTTPData;
import com.serverconnection.HTTPRequest;
import com.stsmobile.dataclass.Specimen;
import com.stsmobile.dataclass.Shipment;

/**
 * STS Application class- creates and stores state by connecting to the server.
 * @author Dave
 *
 */
public class STSApplication extends Application 
{
	//---Static Resources---//
	private static String SERVER_SCRIPTS_URL="http://152.3.83.138/cgi-bin/";
	private static String CONNECTION_ERROR="<error>\n<msg>Error Connecting to Database</msg>\n</error>";
	private static String NO_SHIPMENT_ERROR="<error>\n<msg>No Shipment is Currently Selected!</msg>\n</error>";
	private static String NO_SPECIMENS_ERROR="<error>\n<msg>There are no specimens to update.</msg>\n</error>";
	private static String XML_ERROR="<error>\n<msg>There was an error parsing the XML. " +
	"Please try again later and if the problem persists, contact your administrator.</msg>\n</error>";


	//---State Variables---//
	private static String site_key;
	private static String user_id;
	private static String username;
	private static Shipment current_shipment;
	private static ArrayList<String> search;
	private static boolean logging_out=false;
	private static boolean to_home=false;


	//---Android State-Switch Cases---//
	@Override
	public void onCreate() 
	{
		site_key="";
		user_id="";
		username="";
		current_shipment=null;
	}

	private static Document loadXMLFromString(String xml) throws Exception
	{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		InputSource is = new InputSource(new StringReader(xml));
		return builder.parse(is);
	}

	//---Server Access Methods---//
	/**
	 * Logs a user into the system via the 'sitekey.pl' script.
	 * Given a valid login, returns a randomly generated 'key' and the 'user_id' (in XML form)
	 * which will be used in future calls to access and modify shipment data.
	 * 
	 * This is a POST method, so be careful of duplicate calls. They CAN and WILL alter state.
	 * 
	 * @param user the username of the party who wants to view/receive shipments
	 * @param password the password of the party who wants to view/receive shipments
	 * @return  the XML output of 'sitekey.pl' as a String
	 */
	public static String login(String user, String password)
	{	
		String data = "u="+user+"&p="+password;
		HTTPData result = new HTTPData();

		try {
			result = HTTPRequest.post(SERVER_SCRIPTS_URL+"sitekey.pl", data);
		}
		catch (IOException e) {
			result.content += CONNECTION_ERROR;
		}

		try {
			Document doc = loadXMLFromString(result.content);
			doc.getDocumentElement().normalize();

			String passFail = doc.getDocumentElement().getNodeName();

			if(passFail.equals("success")){
				NodeList nList = doc.getElementsByTagName("sitekey");

				for (int temp = 0; temp < nList.getLength(); temp++) {
					Node nNode = nList.item(temp);
					if (nNode.getNodeType() == Node.ELEMENT_NODE) {

						Element e = (Element) nNode;

						site_key = e.getAttribute("key_value");
						user_id = e.getAttribute("user_id");
					}
				}
			}
		} catch (Exception e) {
			result.content=XML_ERROR;
			e.printStackTrace();
		}

		username=user;
		return result.content;
	}

	public static String sitekeyString(){
		return site_key+" | "+user_id;
	}
	public static String getUsername(){
		return username;
	}
	
	public static String search(String institution_id){
		String data = "uid="+user_id+"&key="+site_key+"&lab_name="+institution_id;
		HTTPData result = new HTTPData();
		search = new ArrayList<String>();
		try {
			result = HTTPRequest.get(SERVER_SCRIPTS_URL+"search.pl"+"?"+data);
		}
		catch (IOException e){
			result.content += CONNECTION_ERROR;
		}
		try {
			Document doc = loadXMLFromString(result.content);
			doc.getDocumentElement().normalize();
			String passFail = doc.getDocumentElement().getNodeName();
			if(passFail.equals("success")){
				NodeList nList = doc.getElementsByTagName("Shipment");
				Node nNode = nList.item(0);

				for (int temp = 0; temp < nList.getLength(); temp++) {
					nNode = nList.item(temp);
					if (nNode.getNodeType() == Node.ELEMENT_NODE) {

						Element e = (Element) nNode;

						String a1 = e.getAttribute("shipment_id");
						search.add(a1);
					}
				}
			}
		}
		catch (Exception e1){
			result.content="<msg>"+e1.getMessage()+"</msg>";
			e1.printStackTrace();
		}
		return result.content;
	}

	/**
	 * Retrieves the shipment with shipment_id and sets to the current_shipment.
	 * 
	 * @param shipment_id The id of the shipment you want to retrieve
	 * @return the XML output of 'shipment.pl' as a String
	 */
	public static String retrieveShipment(String shipment_id)
	{
		String data = "uid="+user_id+"&key="+site_key+"&sh_id="+shipment_id;
		HTTPData result = new HTTPData();

		try {
			result = HTTPRequest.get(SERVER_SCRIPTS_URL+"shipment.pl"+"?"+data);
		}
		catch (IOException e) {
			result.content += CONNECTION_ERROR;
		}

		try {
			Document doc = loadXMLFromString(result.content);
			doc.getDocumentElement().normalize();


			String passFail = doc.getDocumentElement().getNodeName();

			if(passFail.equals("success")){
				
				NodeList nList = doc.getElementsByTagName("Shipment");
					Node nNode = nList.item(0);
					if (nNode.getNodeType() == Node.ELEMENT_NODE) {
						Element e = (Element) nNode;

						String a1 = e.getAttribute("shipment_id");
						String a2 = e.getAttribute("institution_name");
						String a3 = e.getAttribute("lab_name");
						String a4 = e.getAttribute("shipment_status");
						String a5 = e.getAttribute("shipped_date");
						String a6 = e.getAttribute("received_date");

						current_shipment = new Shipment(a1,a2,a3,a4,a5,a6);
					}

				nList = doc.getElementsByTagName("Specimen");

				for (int temp = 0; temp < nList.getLength(); temp++) {
					nNode = nList.item(temp);
					if (nNode.getNodeType() == Node.ELEMENT_NODE) {

						Element e = (Element) nNode;

						String intact="0"+e.getAttribute("intact");
						String damaged="0"+e.getAttribute("damaged");
						String missing="0"+e.getAttribute("missing");
						
						int a1 = Integer.parseInt(e.getAttribute("specimen_id"));
						int a2 = Integer.parseInt(e.getAttribute("study_id"));
						int a3 = Integer.parseInt(e.getAttribute("patient_id"));
						int a4 = Integer.parseInt(e.getAttribute("quantity"));
						int a5 = Integer.parseInt(intact);
						int a6 = Integer.parseInt(damaged);
						int a7 = Integer.parseInt(missing);
						String a8 = e.getAttribute("specimen_title");
						String a9 = e.getAttribute("specimen_description");
						String a10 = e.getAttribute("collection_date");
						String a11 = e.getAttribute("collection_method");
						current_shipment.addSpecimen(
								new Specimen(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11));
					}
				}

			}
		} catch (Exception e) {
			result.content="<msg>"+e.getMessage()+"</msg>";
			e.printStackTrace();
		}

		return result.content;
	}

	/**
	 * Updates all specimens in the current shipment to their saved values.
	 * Be sure to make ALL SPECIMEN CHANGES before calling this method.
	 * 
	 * @return The concatenation of all server responses in XML &lt;response&gt;&lt;/response&gt;.
	 */
	public static String updateShipment()
	{
		if (current_shipment==null){
			return NO_SHIPMENT_ERROR;
		}
		ArrayList<Specimen> toUpdate=current_shipment.getSpecimenList();
		if (toUpdate.isEmpty()){
			return NO_SPECIMENS_ERROR;
		}
		HTTPData result = new HTTPData();
		result.content += "<response>";
		for (Specimen s: toUpdate){
			String data= "uid="+user_id+"&key="+site_key+"&sp_id="+s.getSpecimenID()+
			"&i="+s.getIntact()+"&m="+s.getMissing()+"&d="+s.getDamaged();

			try {
				result.content += "\n"+HTTPRequest.post(SERVER_SCRIPTS_URL+"receive.pl", data).content;
			}
			catch (IOException e) {
				result.content += "\n"+CONNECTION_ERROR;
			}
		}

		result.content += "\n</response>";
		return result.content;
	}

	/**
	 * Logs-out the user from the database by clearing his/her sitekey
	 * 
	 * @return the XML output of 'logout.pl' as a String
	 */
	public static String logout()
	{
		String data = "uid="+user_id+"&key="+site_key;
		HTTPData result = new HTTPData();

		try {
			result = HTTPRequest.get(SERVER_SCRIPTS_URL+"logout.pl"+"?"+data);
		}
		catch (IOException e) {
			result.content += CONNECTION_ERROR;
		}


		return result.content;
	}


	//---State Access Methods---//

	/**
	 * Alters the specimen identified by specimen_id's intact, missing, and damaged attributes
	 * 
	 * This is a POST method, so be careful of duplicate calls, they CAN and WILL alter state.
	 * 
	 * @param specimen_id the unique id number of the specimen you want to alter
	 * @param intact
	 * @param missing
	 * @param damaged
	 * @return -1 if the specimen does not exist. 0 for success.
	 */
	public static int setSpecimen(int specimen_id, int intact, int damaged, int missing)
	{
		Specimen toEdit=current_shipment.getSpecimen(specimen_id);
		if(toEdit==null)
			return -1;

		toEdit.setIntact(intact);
		toEdit.setDamaged(damaged);
		toEdit.setMissing(missing);

		return 0;
	}

	/**
	 * 
	 * @return the current shipment
	 */
	public static Shipment getShipment()
	{
		return current_shipment;
	}
	
	public static String getInstitutionId(){
		return username.substring(1);
	}
	
	public static ArrayList<String> getShipmentList(){
		return search;
	}
	
	public static void wipeData(){
		search = new ArrayList<String>();
		username="";
		user_id="";
		site_key="LOGOUT";
		current_shipment.wipeData();
	}
	
	public static boolean loggingOut(){
		return logging_out;
	}
	
	public static void loggingOut(boolean bool){
		logging_out=bool;
	}
	
	public static boolean toHome(){
		return to_home;
	}
	
	public static void toHome(boolean bool){
		to_home=bool;
	}

}
